/**
 *
 * @author user
 */
import java.awt.BorderLayout;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;

public class DatabaseTableModel extends AbstractTableModel {

       private static final long serialVersionUID = 1L;
       private ArrayList<String> columnNames = new ArrayList<String>();
       private ArrayList<Class<?>> columnTypes = new ArrayList<Class<?>>();
       private ArrayList<ArrayList<Object>> data = new ArrayList<ArrayList<Object>>();
       static Connection con;
       private ResultSetMetaData rsmd;
       public String tableName = "";
       Vector<?> rows = new Vector<Object>();

       public int getRowCount() {
              synchronized (data) {
                     return data.size();
              }
       }

       public int getColumnCount() {
              return columnNames.size();
       }

       public Object getValueAt(int row, int col) {
              synchronized (data) {
                     return data.get(row).get(col);
              }
       }

       public String getColumnName(int col) {
              return columnNames.get(col);
       }

       @SuppressWarnings("unchecked")
       public Class getColumnClass(int col) {
              return columnTypes.get(col);
       }

       public boolean isCellEditable(int row, int col) {
              return true;
       }
//    @SuppressWarnings("unchecked")

       public void setValueAt(Object value, int row, int column) throws IllegalStateException {
              try {
                     // Эта функция
                     // возвращает название поля по его номеру
                     String columnName = getColumnName(column);
                     String query =
                             "UPDATE " + tableName +
                             " SET " + columnName + " = " +
                             dbRepresentation(column, value) +
                             " WHERE ";
                     for (int col = 0; col < getColumnCount(); col++) {
                            String colName = getColumnName(col);
                            if (colName.equals("")) {
                                   continue;
                            }
                            if (col != 0) {
                                   query = query + " and ";
                            }
                            query = query + colName + " = " +
                                    dbRepresentation(col, getValueAt(row, col));
                     }
                     // запрос готов, выполним изменения
                     System.out.println(query);
                     PreparedStatement pstmt = con.prepareStatement(query);
                     pstmt.executeUpdate();  // выполнить изменение
                     // теперь осталось, изменить значение вектора  rows

                     Object val;
                     // без этой функции работать не  будет,
                     // если в setElementAt() вставлять непосредственно
                     // value а не val
                     val = tbRepresentation(column, value);
//                     Vector<Object> dataRow = (Vector) rows.elementAt(row);
  //                   dataRow.setElementAt(val, column);
                     data.get(row).set(column, val);
              } catch (Exception ex) {
                     ex.printStackTrace();
                     System.err.println(ex);
              }

              /*              synchronized (data) {
              data.get(row).set(col, obj);
              fireTableCellUpdated (row, col);
              } */
       }

       public Object tbRepresentation(int column, Object value) throws NumberFormatException {
              Object val;
              int type;
              if (value == null) {
                     return "null";
              }
              try {
                     type = rsmd.getColumnType(column + 1);
              } catch (SQLException e) {
                     e.printStackTrace();
                     return value.toString();
              }
              switch (type) {
                     case Types.BIGINT:
                            return val = new Long(value.toString());
                     case Types.TINYINT:
                     case Types.SMALLINT:
                     case Types.DATE:
                            return value.toString();
                    // case Types.VARCHAR:
                      //      return value.toString();
                     case Types.INTEGER:
                            return val = new Integer(value.toString());
                     case Types.REAL:
                     case Types.FLOAT:
                     case Types.DOUBLE:
                            return val = new Double(value.toString());
                     default:
                            return "\'" + value.toString() + "\'";
              }
       }

       public String dbRepresentation(int column, Object value) {
              int type;

              if (value == null) {
                     return "null";
              }
              try {
                     type = rsmd.getColumnType(column + 1);
              } catch (SQLException e) {
                     e.printStackTrace();
                     return value.toString();
              }
              switch (type) {
                     case Types.INTEGER:
                     //case Types.VARCHAR:
                            return value.toString();
                     case Types.DOUBLE:
                     case Types.DATE:
                            return value.toString();
                     default:
                            return "\'" + value.toString() + "\'";
              }
       }

       public void setDataSource(ResultSet rs) throws SQLException, ClassNotFoundException {
              //ResultSetMetaData rsmd = rs.getMetaData();
              rsmd = rs.getMetaData();
              columnNames.clear();
              columnTypes.clear();
              data.clear();
              //rows

              int columnCount = rsmd.getColumnCount();
              for (int i = 0; i < columnCount; i++) {
                     columnNames.add(rsmd.getColumnName(i + 1));
                     Class<?> type = Class.forName(rsmd.getColumnClassName(i + 1));
                     columnTypes.add(type);
              }
              fireTableStructureChanged();
              while (rs.next()) {
                     ArrayList<Object> rowData = new ArrayList<Object>();
                     for (int i = 0; i < columnCount; i++) {
                            if (columnTypes.get(i) == String.class) {
                                   rowData.add(rs.getString(i + 1));
                            } else {
                                   rowData.add(rs.getObject(i + 1));
                            }
                     }
                     synchronized (data) {
                            data.add(rowData);
                            this.fireTableRowsInserted(data.size() - 1, data.size() - 1);
                     }
              }
       }


       public static void main(String[] args) {
              try {
                     //Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
                     String url = "jdbc:mysql://127.0.0.1:3306/";
                     String user = "root";
                     String password = "123456";
                     String query = "select * from dase_1251.tab1";
                     con = DriverManager.getConnection(url, user, password);
                     Statement st = con.createStatement();
                     ResultSet rs = st.executeQuery(query);
                     DatabaseTableModel model = new DatabaseTableModel();
                     model.tableName = "dase_1251.tab1";
                     model.setDataSource(rs);
                     JTable table = new JTable(model);
                     JPanel panel = new JPanel(new BorderLayout());
                     panel.add(new JScrollPane(table), BorderLayout.CENTER);
                     JFrame frame = new JFrame("Лабораторна робота № 5");
                     frame.setLocationRelativeTo(null);
                     frame.setSize(500, 400);
                     frame.setContentPane(panel);
                     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                     frame.setVisible(true);
              } catch (SQLException e) {
                     e.printStackTrace();
              } catch (ClassNotFoundException e) {
                     e.printStackTrace();
              }
       }
}
